"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
"""

import configparser
import traceback
import logging
import time
import sys
import os
from xml.dom.minidom import parse

import json5


# logger
tools_logger = logging.getLogger('part-tools')

"""
file configs
"""


def report_file_error(filetype: str, error_type, filename: str, stack: any):
    error = traceback.format_exc()
    if isinstance(error_type, FileNotFoundError):
        log = 'no {} file was found!: \n file name: {} \n file type: {} \n stack: {} \n traceback: {}'.format(filetype, filename, filetype, stack, error)
    elif isinstance(error_type, KeyError):
        log = 'no stack in %s file: %s \n file type: %s \n stack: %s' % (filetype, filename, filetype, stack)
    else:
        log = 'some error has been found! \n error type: %s \n file name: %s \n file type: %s \n stack: %s' % (error_type, filename, filetype, stack)
    tools_logger.exception(log)


def config(file_name: str, stack=None):
    f_type = file_name[file_name.rfind('.') + 1:]  # 从最后一个.到末尾 (截取文件格式)
    try:
        if (f_type == 'json5') or (f_type == 'json'):
            try:
                with open(file_name, 'r', encoding='utf-8') as jf:  # jf -> json file
                    rd = json5.load(jf)
            except UnicodeDecodeError:
                with open(file_name, 'r', encoding='gbk') as jf:
                    rd = json5.load(jf)
                tools_logger.info('文件 %s 解码错误，已重新使用gbk编码打开' % file_name)
            if stack is not None:
                rd = rd[stack]
            return rd
        elif f_type == 'xml':
            xml_load = parse(file_name)
            if stack is not None:
                xml_get = xml_load.getElementsByTagName(stack)
                return xml_get
            else:
                return xml_load
        elif (f_type == 'config') or (f_type == 'conf'):
            cp = configparser.ConfigParser()  # cp -> config parser
            cp.read(file_name)  # config parser -> reader
            rd = {}
            for section in cp.sections():
                rd[section] = {}
                for data in cp[section]:
                    rd[section][data] = cp[section][data]
            if stack:
                rd = rd[stack]
            return rd
    except FileNotFoundError:
        log = 'no {} file was found!: \n file name: {} \n file type: {} \n stack: {}'.format(f_type, file_name, f_type, stack)
        tools_logger.error(log)
        raise
    except KeyError:
        log = 'no stack in {} file {} was found! \n file type: {} \n file name: {} \n stack: {}'.format(f_type, file_name, f_type, file_name, stack)
        tools_logger.error(log)
        raise
    except Exception as exp:
        log = 'some error has been found!\n error type: {} \n file name: {} \n file type: {} \n stack: {}'.format(type(exp), file_name, f_type, stack)
        tools_logger.error(log)
        raise



def get_At(name, in_xml, need_type=str):
    """
    get Attribute from a XML tree
    will raise TypeError if input is not str or list
    XML no!   Json5 yes!
    """
    name_type = type(name)
    if name_type == list:
        At_list = []
        for need_name in name:
            if in_xml.hasAttribute(need_name):
                get = in_xml.getAttribute(need_name)
                At_list.append(need_type(get))
            else:
                continue
        return At_list
    elif name_type == str:
        if in_xml.hasAttribute(name):
            At = in_xml.getAttribute(name)
        else:
            return None
    else:
        raise TypeError('only str and list type is ok but you give me a' + name_type + 'type')
    return need_type(At)


def default_name_handler(name_: str) -> str:
    """
    won't change the string
    just return one
    """
    name = name_
    name = name.replace('{time.time}', str(time.time()))
    name = name.replace('{dir}', str(os.getcwd()))
    name = name.replace('{py_v}', str(sys.version.split(' ')[0]))
    return name


def name_handler(name: str, formats: dict = None) -> str:
    if formats is None:
        return default_name_handler(name)
    name = default_name_handler(name)
    for need_replace in formats:
        replace = formats[need_replace]
        if need_replace == '{date}':
            if '{date}' in formats:
                replace = time.strftime(formats['{date}'], time.gmtime(time.time()))
            else:
                replace = time.strftime(main_config_file['runtime']['date_fmt'], time.gmtime(time.time()))
        name = name.replace(need_replace, replace)
    return name


"""
some tools
"""


def format_bool(thing):
    yes = ['True', 'TRUE', 'true', '1', 1, True]
    no = ['False', 'FALSE', 'false', '0', 0, False]
    if thing in yes:
        return True
    elif thing in no:
        return False
    else:
        raise ValueError("Need a 'like bool' not anything else")


level_ = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL',
          logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]


def log_level(level):
    if level in level_:
        if (level == 'DEBUG') or (level == logging.DEBUG):
            return logging.DEBUG
        if (level == 'INFO') or (level == logging.INFO):
            return logging.INFO
        if (level == 'WARNING') or (level == logging.WARNING):
            return logging.WARNING
        if (level == 'ERROR') or (level == logging.ERROR):
            return logging.ERROR
        if (level == 'CRITICAL') or (level == logging.CRITICAL):
            return logging.CRITICAL
    else:
        raise ValueError('Need a like logging.level thing not anything else')
